#ifndef _GEOMETRY_H_
#define _GEOMETRY_H_

#ifdef WIN32
  #define M_PI 3.14159265359
#endif

struct Vector3f {
    float x;
	float y;
	float z;

	Vector3f(float a = 0, float b = 0, float c = 0) : x(a), y(b), z(c) {}

	Vector3f(const float a[3]) {
		x = a[0];
		y = a[1];
		z = a[2];
	}

	Vector3f operator+(const Vector3f& a) {
		return Vector3f(x + a.x, y + a.y, z + a.z);
	}

	Vector3f operator+(const float a[3]) {
		return Vector3f(x + a[0], y + a[1], z + a[2]);
	}

	Vector3f operator-(const Vector3f& a) {
		return Vector3f(x - a.x, y - a.y, z - a.z);
	}

	Vector3f operator-(const float a[3]) {
		return Vector3f(x - a[0], y - a[1], z - a[2]);
	}

	// scale
	Vector3f operator*(const float a) {
		return Vector3f(x * a, y * a, z * a);
	}

	Vector3f operator/(const float a) {
		return Vector3f(x / a, y / a, z / a);
	}

	// dot product
	float operator*(const Vector3f& a) {
		return (x * a.x) + (y * a.y) + (z * a.z);
	}

// ******************************************************************* //

	void operator+=(const Vector3f& a) {
		x += a.x;
		y += a.y;
		z += a.z;
	}

	void operator+=(const float a[3]) {
		x += a[0];
		y += a[1];
		z += a[2];
	}

	void operator-=(const Vector3f& a) {
		x -= a.x;
		y -= a.y;
		z -= a.z;
	}

	void operator-=(const float a[3]) {
		x -= a[0];
		y -= a[1];
		z -= a[2];
	}
	
	// scale
	void operator*=(const float a) {
		x *= a;
		y *= a;
		z *= a;
	}

	void operator/=(const float a) {
		x /= a;
		y /= a;
		z /= a;
	}

	// cross product
	Vector3f cross(const Vector3f& a) {
		Vector3f c;
		c.x = (y * a.z) - (z * a.y);
		c.y = (z * a.x) - (x * a.z);
		c.z = (x * a.y) - (y * a.x);
		return c;
	}

	Vector3f unit() {
		Vector3f u;
		Vector3f v = Vector3f(x, y, z);
		float norm = 0.0f;

		norm = sqrt(v * v);
		u = v * (1.0f / norm);
		return u;
	}

	float mag() {
		float m = 0.0f;
		m = sqrt((x * x) + (y * y) + (z * z));
		return m;
	}
};

/*

float normalize(Vector3f n)
{
  float norm;

  norm = sqrt(dotProd(n, n));
  scale(n, (float)1.0/norm);

  return norm;
}


double normalize(Vector3d n)
{
  double norm;

  norm = sqrt(dotProd(n, n));
  scale(n, 1.0/norm, n);

  return norm;
}


void normal(Vector3f n, const Vector3f p, const Vector3f q, const Vector3f r)
{
  Vector3f u, v;

  // right hand system, CCW triangle
  sub(u, q, p);
  sub(v, r, p);

  // plane normal
  vecProd(n, u, v);
  normalize(n);
}


void normal(Vector3d n, const Vector3d p, const Vector3d q, const Vector3d r)
{
  Vector3d u, v;

  // right hand system, CCW triangle
  sub(u, q, p);
  sub(v, r, p);

  // plane normal
  vecProd(n, u, v);
  normalize(n);
}


/*
typedef float Vector3f[3];
typedef double Vector3d[3];

typedef float Vector4f[4];
typedef double Vector4d[4];

typedef float Matrix3f[3][3];
typedef double Matrix3d[3][3];

typedef float Matrix4f[4][4];
typedef double Matrix4d[4][4];


void add(Vector3f sum, const Vector3f v);
void add(Vector3f sum, const Vector3f v1, const Vector3f v2);
void add(Vector3d sum, const Vector3d v1, const Vector3d v2);

void sub(Vector3f diff, const Vector3f v);
void sub(Vector3f diff, const Vector3f v1, const Vector3f v2);
void sub(Vector3d diff, const Vector3d v1, const Vector3d v2);

void scale(Vector3f mul, float s);
void scale(Vector3f mul, float s, const Vector3f v1);
void scale(Vector3d mul, double s, const Vector3d v1);

float dotProd(const Vector3f a, const Vector3f b);
double dotProd(const Vector3d a, const Vector3d b);

void vecProd(Vector3f n, const Vector3f u, const Vector3f v);
void vecProd(Vector3d n, const Vector3d u, const Vector3d v);

float normalize(Vector3f n);
double normalize(Vector3d n);

void normal(Vector3f n, const Vector3f p, const Vector3f q, const Vector3f r);
void normal(Vector3d n, const Vector3d p, const Vector3d q, const Vector3d r);

void emptyMatrix(Matrix3f m);
void emptyMatrix(Matrix4f m);

void setRowVectors(Matrix4f m, const Vector3f u, const Vector3f v, const Vector3f w);
void setColVectors(Matrix4f m, const Vector3f u, const Vector3f v, const Vector3f w);

void transpose(Matrix4f m, const Matrix4f m1);

void scaleMatrix(Matrix3f m, float s);

void scaleMatrix(Matrix4f m, float s);
void scaleMatrix(Matrix4f m, float s, const Matrix4f m1);

void addMatrix(Matrix3f m1, const Matrix3f m2);
void addMatrix(Matrix4f m1, const Matrix4f m2);

void addScaledMatrix(Matrix3f m1, const float s, const Matrix3f m2);
void addScaledMatrix(Matrix4f m1, const float s, const Matrix4f m2);

void subMatrix(Matrix3f m1, const Matrix3f m2);
void subMatrix(Matrix4f m1, const Matrix4f m2);

// m1 is left, m2 is right matrix, multiplication from right-to-left
void multMatrix(Matrix4f m, const Matrix4f m1, const Matrix4f m2);

// apply 4x4 matrix to 3D vector
void multVector(Vector3f u, const Matrix4f m, const Vector3f v);

*/

#endif